﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Timers;
using TwitterAPI;
using System.Windows;
using VsSpeakerCompanion;
using System.ComponentModel.Composition;
using System.Windows.Threading;
using System.Windows.Input;
using VsSpeakerCompanion.UI;

namespace SpeedWidget
{
    /// <summary>
    /// Shows what the audience thinks about the pace of the talk
    /// Will try to get the speaker attention if the audience thinks he/she is going too fast or too slow
    /// </summary>
    class Widget : IWidget
    {
        // we will be using this service to animate the widget
        private IWidgetAnimationService widgetAnimationService;
        // our UI
        private SpeedView view;
        // Couple of lists to keep track of received feedback
        private List<string> fastVoters;
        private List<string> slowVoters;

        public Widget(TwitterService twitterService, IWidgetAnimationService widgetAnimationService)
        {
            this.view = new SpeedView();

            // list to clicks on our widget (this means the speaker  the received feedback)
            this.view.MouseDown +=new System.Windows.Input.MouseButtonEventHandler(view_MouseDown);
            this.widgetAnimationService = widgetAnimationService;

            fastVoters = new List<string>();
            slowVoters = new List<string>();

            // register the two feedback messages this widget understands
            twitterService.RegisterCommand("too fast", ProcessTooFastMessages);
            twitterService.RegisterCommand("too slow", ProcessTooSlowMessages);

            view.Dispatcher.Invoke(new Action(() => { view.Speed = 0.5; }));
        }

        /// <summary>
        /// Handles the mouse click event on our widget
        /// </summary>
        /// <param name="source"></param>
        /// <param name="e"></param>
        private void view_MouseDown(object source, MouseButtonEventArgs e)
        {
            // Clicking on the widget means the speaker acknowledged the received feedback and:
            // a) the animation should stop and b) the visual indication of too fast or too slow should be reset
            Reset();
        }

        /// <summary>
        /// Keep the count of "too fast" received messages
        /// </summary>
        /// <param name="feedItems"></param>
        private void ProcessTooFastMessages(IEnumerable<FeedItem> feedItems)
        {
            // each user has only a single vote, but he/she can change it at anytime
            // make sure if the user voting has voted before we always remove the previous vote
            feedItems.ToList().ForEach(item => { if (slowVoters.Contains(item.User)) slowVoters.Remove(item.User); });
            feedItems.ToList().ForEach(item => { if (!fastVoters.Contains(item.User)) fastVoters.Add(item.User); });

            // update our UI with the new vote count
            UpdateSpeed();
        }

        /// <summary>
        /// Keep the count of "too slow" received messages
        /// </summary>
        /// <param name="feedItems"></param>
        private void ProcessTooSlowMessages(IEnumerable<FeedItem> feedItems)
        {
            // each user has only a single vote, but he/she can change it at anytime
            // make sure if the user voting has voted before we always remove the previous vote
            feedItems.ToList().ForEach(item => { if (fastVoters.Contains(item.User)) fastVoters.Remove(item.User); });
            feedItems.ToList().ForEach(item => { if (!slowVoters.Contains(item.User)) slowVoters.Add(item.User); });

            // update our UI with the new vote count
            UpdateSpeed();
        }

        private void UpdateSpeed()
        {
            int totalVotes = fastVoters.Count + slowVoters.Count;
            if (totalVotes > 0)
            {
                widgetAnimationService.Start(this);
                double tooFastPerc = Convert.ToDouble(fastVoters.Count) / Convert.ToDouble(totalVotes);
                double speed = tooFastPerc;

                view.Dispatcher.Invoke(new Action<double>(speedArgument => { view.Speed = speedArgument; }), speed);
            }
            else
            {
                view.Dispatcher.Invoke(new Action(() => { view.Speed = 0.5; }));
            }
        }

        public UIElement VisualElement
        {
            get
            {
                return view;
            }
        }

        /// <summary>
        /// Resets our data and start considering new feedback from zero
        /// </summary>
        public void Reset()
        {
            fastVoters = new List<string>();
            slowVoters = new List<string>();
            view.Dispatcher.Invoke(new Action(() => { view.Speed = 0.5; }));
            widgetAnimationService.Stop(this);
        }
    }
}